<?php
include "wx.config.php";

define("RouterApi", serialize($RouterApi));

$wx_author = new wx_author();
$wx_author->init();

class wx_author{
    private $RouterApi;
    // 构造函数
  	public function __construct() {
    	$this->RouterApi = unserialize(RouterApi);
  	}
	public function init(){
		//当前server路径
    	$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    	$domainname = $protocol.$_SERVER[HTTP_HOST];

		if (!isset($_GET['code'])){
			header("location: ".$domainname."/SJBWEB/Public/phpfile/common/backerror.html?type=code");
			exit;
		}else{
			$code= $_GET['code'];
		}

		//获取openid
		$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->RouterApi["appid"]."&secret=".$this->RouterApi["appSecret"]."&code=".$code."&grant_type=authorization_code";
		$rtn = json_decode($this->http_request($url),TRUE);
		$this->wxlog($rtn,__FILE__,__LINE__,'微信openid返回值');//记录微信回调
		if(!isset($rtn["openid"]) || $rtn["openid"] == "" || $rtn["openid"] == null || $rtn["openid"] == "null"){
			header("location: ".$domainname."/SJBWEB/Public/phpfile/common/backerror.html?type=openid");
			exit;
		}


		//拼接页面GET参数
        $state = urldecode($_GET["state"]);

        $queryData = explode('&', $state);
        $this->wxlog($queryData,__FILE__,__LINE__,"授权回调接收参数");

        $queryString = "";
        $target = "";
        foreach ($queryData as $val)
        {
            $arr = explode('=', $val);
            if($arr[0] == "target") {
                $target = $arr[1].".html";//目标页面
            }else{
                $queryString .= $arr[0].'='.$arr[1]."&";
            }
        }
        if($target == ""){
            $this->wxlog($queryString,__FILE__,__LINE__,"授权回调重定向无目标页面");
            exit;
        }
        if(strlen($queryString) > 0){
            $queryString = $target."?".substr($queryString,0,strlen($queryString)-1);
        }else{
            $queryString = $target;
        }

    	$this->authcode($rtn["openid"],'encode','resultData');
		$this->wxlog($domainname."/SJBWEB/Public/phpfile/common/".$queryString,__FILE__,__LINE__,"授权回调重定向");
		header("location: ".$domainname."/SJBWEB/Public/phpfile/common/".$queryString);
		exit;
	}

	// $string： 明文 或 密文
	// $operation：DECODE表示解密,其它表示加密
	// $key： 密匙
	// $expiry：密文有效期
    public function authcode($string, $operation = 'DECODE', $cookiename='', $expiry = 0) {
	    //$this->strLog('开始',$this->get_total_millisecond());
	    // 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
	    $ckey_length = 12;
	    // 密匙
	    $key = md5($this->RouterApi["wx_secret"]);

	    // 密匙a会参与加解密
	    $keya = md5(substr($key, 0, 16));
	    // 密匙b会用来做数据完整性验证
	    $keyb = md5(substr($key, 16, 16));
	    // 密匙c用于变化生成的密文
	    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
	    // 参与运算的密匙
	    $cryptkey = $keya.md5($keya.$keyc);
	    $key_length = strlen($cryptkey);
	    // 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，解密时会通过这个密匙验证数据完整性
	    // 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确
	    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
	    $string_length = strlen($string);
	    $result = '';
	    $box = range(0, 255);
	    $rndkey = array();
	    // 产生密匙簿
	    for($i = 0; $i <= 255; $i++) {
	        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
	    }
	    // 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度
	    for($j = $i = 0; $i < 256; $i++) {
	        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
	        $tmp = $box[$i];
	        $box[$i] = $box[$j];
	        $box[$j] = $tmp;
	    }
	    // 核心加解密部分
	    for($a = $j = $i = 0; $i < $string_length; $i++) {
	        $a = ($a + 1) % 256;
	        $j = ($j + $box[$a]) % 256;
	        $tmp = $box[$a];
	        $box[$a] = $box[$j];
	        $box[$j] = $tmp;
	        // 从密匙簿得出密匙进行异或，再转成字符
	        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
	    }
	    if($operation == 'DECODE') {
	        // substr($result, 0, 10) == 0 验证数据有效性
	        // substr($result, 0, 10) - time() > 0 验证数据有效性
	        // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性
	        // 验证数据有效性，请看未加密明文的格式
	        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
	            return substr($result, 26);
	        }
	        else {
	            return '';
	        }
	    } else {
	        // 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
	        // 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
	        $strcode = $keyc.str_replace('=', '', base64_encode($result));
	        if($cookiename!='')
	        {
	            setcookie("resultData",null,'/');
	            setcookie("resultData",$strcode,time()+3600*24*30,'/');
	        }
	        //$this->strLog('结束',$this->get_total_millisecond());
	        return $strcode;
	    }
	}

	/**
     * 发送http请求 支持get和post
     * @param string $url
     * @param string $data post的数据
     */
    public function http_request($url,$data = null)
    {
    	$curl = curl_init();
		curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    	curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    	if (!empty($data)) {
			curl_setopt($curl, CURLOPT_POST, 1);
			curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
    	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    	$output = curl_exec($curl);
		curl_close($curl);
        return $output;
    }


	//打印日志
	public function wxlog($arr,$file = 0,$line = 0,$flag = "array"){
		if(is_array($arr)){
			$log = $arr;
		}else{
			$log["value"] = $arr;
		}
		$content = "File => ".end(explode('\\',$file))." on line:".$line."\r\n";
		$content .= date("Y/m/d H:i:s")." ".$flag."(";

		foreach ($log as $key => $value) {
			if(is_array($value)){
				$content .= "\r\n    '".$key."' => '".urldecode(json_encode($value))."'";
			}else{
				$content .= "\r\n    '".$key."' => '".$value."'";
			}
		}
		$content .= "\r\n)\r\n\r\n";
        $log_filename = 'log/'.date("Ymd").".log";
        if(file_exists($log_filename)){
			file_put_contents($log_filename, $content ,FILE_APPEND);
        }else{
        	file_put_contents($log_filename, $content);
        }
	}
}
?>